const fs = require("fs");
const formidable = require("formidable");
const path = require("path");
const FileService = require("../service/FileService");
const response = require("../utils/response");
const config = require("@/config/index");
const { nextId } = require("../utils/genrate_nextId");
// const writeLog = require("../utils/writeLog");
const dayjs = require("dayjs");
const { pool } = require("../db/index");
const { Readable } = require("stream"); // 导入 Readable 和 Writable
// 设置一个用于保存上传文件的目录
const uploadDir = path.join(__dirname, "uploads");
if (!fs.existsSync(uploadDir)) {
  fs.mkdirSync(uploadDir);
}
class FileController {
  /**
   * 新增数据,小文件上传
   * @param {Context} ctx 上下文
   */
  async addFile(req, res) {
    //检查是否有空间id
    if (!req.query.spaceId) {
      return res.status(400).send("Space ID is required.");
    }
    //检查空间id目录是否存在
    const spaceDir = path.join(config.fileStorageDir, req.query.spaceId);
    if (!fs.existsSync(spaceDir)) {
      return res.status(400).send("Space ID directory does not exist.");
    }
    // 创建一个新的formidable表单解析实例
    const form = new formidable.IncomingForm({
      uploadDir: config.fileStorageDir + "/" + req.query.spaceId, // 设置文件上传的目录
      keepExtensions: true, // 保留文件的扩展名
    });
    // 解析表单数据,限制解析200MB一下文件哦
    form.parse(req, async (err, fields, { file }) => {
      if (err) {
        //只要不是服务器停止的异常，数据不完整会被自动删除！
        // 处理错误
        return res.status(500).send("Error uploading file.");
      }
      try {
        const result = await FileService.isReuseFile(
          file[0].newFilename,
          fields.spaceId[0]
        );
        if (result.length) {
          res.json(response.error(`新增文件名称已存在，请修改！`, null, 200));
        } else {
          await FileService.addFileInfo([
            nextId(),
            fields.spaceId[0],
            file[0].newFilename,
            file[0].size,
            fields.fileType[0],
            fields.remark[0],
            fields.status ? fields.status[0] : 1,
            fields.addressOrgin ? fields.addressOrgin : "3",
          ]);
          //根据运行环境拼接返回文件地址
          let fileUrl = `http://${process.env.DB_HOST}:${
          process.env.PROXY_PORT
            ? process.env.PROXY_PORT
            : process.env.SERVICE_PORT
        }/public/${fields.spaceId[0]}/${file[0].newFilename}`;
          res.json(response.success({ fileUrl }, "上传成功并保存到数据库"));
        }
      } catch (error) {
        // 删除成功的文件吧，要来也无用
        if (fs.existsSync(file[0].filepath)) {
          //客户端断传删除不完整的数据文件
          fs.unlinkSync(file[0].filepath);
        }
        res.status(500).send(`上传文件成功但保存到数据库时出错: ${error}`);
      }
    });
  }
  // 在新建一个大文件分片整合上传
  async addBigFile(req, res) {
    // 检查是否所有分片都已上传
    async function checkAllChunksUploaded(tempDir, fileHash, totalChunks) {
      for (let i = 0; i < totalChunks; i++) {
        const chunkFileName = `${fileHash}-${i}`;
        const chunkFilePath = path.join(tempDir, chunkFileName);
        if (!fs.existsSync(chunkFilePath)) {
          return false;
        }
      }
      return true;
    }

    // 合并所有分片文件
    async function mergeChunks(tempDir, fileHash, totalChunks, finalFilePath) {
      const writeStream = fs.createWriteStream(finalFilePath);
      for (let i = 0; i < totalChunks; i++) {
        const chunkFileName = `${fileHash}-${i}`;
        const chunkFilePath = path.join(tempDir, chunkFileName);
        const readStream = fs.createReadStream(chunkFilePath);
        await new Promise((resolve, reject) => {
          readStream.pipe(writeStream, { end: false });
          readStream.on("end", resolve);
          readStream.on("error", reject);
        });
      }
      writeStream.end();
    }
    // 检查是否有空间id
    if (!req.query.spaceId) {
      return res.status(400).send("Space ID is required.");
    }
    // 检查空间id目录是否存在
    const spaceDir = path.join(config.fileStorageDir, req.query.spaceId);
    if (!fs.existsSync(spaceDir)) {
      return res.status(400).send("Space ID directory does not exist.");
    }
    //检查fileHash文件是否存在
    // 获取分片信息
    const {
      fileHash,
      fileName,
      fileType,
      remark,
      currentSize,
      totalSize,
      chunkIndex,
      totalChunks,
      status,
      addressOrgin,
    } = req.body;
    const finalFilePath = path.join(spaceDir, fileName);
    if (fs.existsSync(finalFilePath)) {
      return res.status(400).send("File already exists.");
    }

    // 创建一个临时存放分片文件的目录
    let tempDir, uploadId;
    if (!req.body.uploadId) {
      // 处理第一个分片，生成唯一 ID 和时间戳
      const timestamp = Math.floor(Date.now() / 1000);
      uploadId = `${nextId()}_${timestamp}`;
      tempDir = path.join(spaceDir, uploadId);

      // 创建临时目录
      if (!fs.existsSync(tempDir)) {
        fs.mkdirSync(tempDir, { recursive: true });
      }
    } else {
      // 处理后续分片
      uploadId = req.body.uploadId;
      tempDir = path.join(spaceDir, uploadId);

      // 检查临时目录是否存在
      if (!fs.existsSync(tempDir)) {
        return res.status(400).send("临时目录不存在，请重新上传第一个分片");
      }
    }

    try {
      const chunkFileName = `${fileHash}-${chunkIndex}`;
      const chunkFilePath = path.join(tempDir, chunkFileName);

      // 保存分片文件
      const writeStream = fs.createWriteStream(chunkFilePath);
      await new Promise((resolve, reject) => {
        // 使用 req.file.buffer 写入文件
        writeStream.write(req.file.buffer);
        writeStream.end();
        writeStream.on("finish", resolve);
        writeStream.on("error", reject);
      });

      // 检查是否所有分片都已上传
      const allChunksUploaded = await checkAllChunksUploaded(
        tempDir,
        fileHash,
        totalChunks
      );
      if (allChunksUploaded) {
        // 合并所有分片文件
        await mergeChunks(tempDir, fileHash, totalChunks, finalFilePath);

        fs.rmSync(tempDir, { recursive: true, force: true }); // 完成时递归删除目录和分片，force 选项确保即使文件被占用也尝试删除
        //根据运行环境拼接返回文件地址
        let fileUrl = `http://${process.env.DB_HOST}:${
          process.env.PROXY_PORT
            ? process.env.PROXY_PORT
            : process.env.SERVICE_PORT
        }/public/${req.query.spaceId}/${fileName}`;
        //保存到数据库
        await FileService.addFileInfo([
          nextId(),
          req.query.spaceId,
          fileName,
          totalSize,
          fileType,
          remark,
          status ? status : 1,
          addressOrgin ? addressOrgin : "3",
        ]);
        res.json(
          response.success(
            { fileUrl, uploadId },
            "大文件上传成功并保存到数据库"
          )
        );
      } else {
        if (req.body.uploadId) {
          res.json(response.success({}, "分片上传成功"));
          return;
        }
        res.json(response.success({ uploadId }, "分片上传成功"));
      }
    } catch (error) {
      //意外失败了，清理可能存在的临时文件和目录
      try {
        // 使用 fs.rmSync 替代 fs.rmdirSync 进行递归删除
        if (fs.existsSync(tempDir)) {
          fs.rmSync(tempDir, { recursive: true, force: true }); // 递归删除目录，force 选项确保即使文件被占用也尝试删除
        }
      } catch (rmError) {
        console.error("删除临时目录时出错:", rmError);
      } finally {
        res.status(500).send(`上传分片文件时出错: ${error}`);
      }
    }
  }

  /**
   * 删除文件数据
   * @param {Context} ctx
   */
  async delFile(req, res, next) {
    try {
      const { fileId } = req.query;
      const existingFile = await FileService.getFileInfo(fileId);
      if (existingFile[0].length === 0) {
        res.json(response.error(`未找到ID为${fileId}的文件，无法删除`, null));
        return;
      }
      const fileInfo = existingFile[0];
      const filePath = path.join(
        config.fileStorageDir,
        fileInfo.spaceId + "/" + fileInfo.fileName
      );
      // 先从数据库中删除文件记录
      const deleteDbResult = await FileService.delFile(fileId, () => {
        if (fs.existsSync(filePath)) {
          return fs.unlinkSync(filePath);
        } else {
          console.log(`未找到该文件:${filePath}`);
          return Promise.resolve(`未找到该文件:${filePath}`);
        }
      });
      res.json(response.success(deleteDbResult, "文件删除成功"));
    } catch (error) {
      next(error);
    }
  }
  /**
   * 修改文件数据
   * @param {Context} ctx
   */
  async updateFile(req, res, next) {
    try {
      const { body } = req;
      const existingFile = await FileService.getFileInfo(body.fileId);
      if (existingFile.length === 0) {
        res.json(
          response.error(`未找到ID为${body.fileId}的文件，无法修改`, null)
        );
        return;
      }
      const beforeInfo = existingFile[0];
      const oldFilePath = path.join(
        config.fileStorageDir,
        beforeInfo.spaceId + "/" + beforeInfo.fileName
      );
      //获取原文件后缀类型
      const fileExtension = path.extname(oldFilePath);
      const newFilePath = path.join(
        config.fileStorageDir,
        body.spaceId + "/" + body.fileName + fileExtension
      );
      if (fs.existsSync(oldFilePath)) {
        if (!body.fileName) {
          return res.json(response.error("文件名不能为空"));
        }
        body.fileName = body.fileName + fileExtension;
        const data = await FileService.updateFileInfo(body, () => {
          return fs.renameSync(oldFilePath, newFilePath);
        });
        res.json(response.success(data));
      } else {
        res.json(response.error("修改文件本身不存在"));
      }
    } catch (error) {
      next(error);
    }
  }
  /**
   * 查询文件数据列表
   * @param {Context} ctx
   */
  queryFileList(req, res, next) {
    try {
      const { query } = req;
      FileService.getFileListPage(query)
        .then((data) => {
          res.json(
            response.success({
              list: data[0].map((item) => {
                item.creatTime = dayjs(item.creatTime).format(
                  "YYYY-MM-DD HH:mm:ss"
                );
                item.updateTime = dayjs(item.updateTime).format(
                  "YYYY-MM-DD HH:mm:ss"
                );
                item.fileFullPath = `http://${process.env.DB_HOST}:${
                  process.env.PROXY_PORT
                    ? process.env.PROXY_PORT
                    : process.env.SERVICE_PORT
                }/public/${item.spaceId}/${item.fileName}`;
                return item;
              }),
              total: data[1][0]["count(*)"],
            })
          );
        })
        .catch((err) => {
          res.json(response.error());
        });
    } catch (error) {
      next(error);
    }
  }
}
module.exports = new FileController();
